package com.gulimall.ware.config.mq;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.common.to.OrderTo;
import com.common.to.mq.StockDetailTo;
import com.common.to.mq.StockLockedTo;
import com.common.utils.R;
import com.gulimall.ware.dao.WareOrderTaskDao;
import com.gulimall.ware.dao.WareSkuDao;
import com.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.gulimall.ware.entity.WareOrderTaskEntity;
import com.gulimall.ware.feign.OrderFeignService;
import com.gulimall.ware.service.impl.WareOrderTaskDetailServiceImpl;
import com.gulimall.ware.service.impl.WareOrderTaskServiceImpl;
import com.gulimall.ware.service.impl.WareSkuServiceImpl;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;

/**
 * @Author Rookie-6688
 * @Description
 * @Create 2021-05-10 11:07
 */
@Component
@Slf4j
@RabbitListener(queues = "stock.release.stock.queue")
public class MyListener {

    @Resource
    private WareSkuServiceImpl wareSkuServiceImpl;
    @Resource
    private WareOrderTaskServiceImpl wareOrderTaskServiceImpl;
    @Resource
    private WareOrderTaskDetailServiceImpl wareOrderTaskDetailServiceImpl;

    /**
     * MQ客户端接收延时队列消息处理：解锁库存
     * 库存发生异常的两个场景：
     * 1、	未找到库存，锁库存失败。这种情况会抛出异常，所以整个方法事务会回滚，那么对应的锁库存记录也就没有，那么其他成功锁库存的也会回滚，也就无需解锁库存
     * 2、	找到库存，说明锁库存成功，但是在主业务事务中的其他操作抛出异常，导致锁库存未回滚，所以需要解锁库存
     *
     * @param stockLockedTo
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitHandler
    @Transactional
    public void handlerStockLockedRelease(StockLockedTo stockLockedTo, Message message, Channel channel) throws IOException {
        try {
            log.info("库存解锁消息-------------------------");
            log.info(stockLockedTo.getId()+"------"+stockLockedTo.getDetailTo()+"-----------");
            WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskServiceImpl.getById(stockLockedTo.getId());
            // 查询最新的订单详情数据
            WareOrderTaskDetailEntity taskDetailEntity = wareOrderTaskDetailServiceImpl.getById(stockLockedTo.getDetailTo().getId());
            wareSkuServiceImpl.releaseStock(wareOrderTaskEntity,taskDetailEntity, message, channel);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            // 如果发生异常将消息重新放入队列
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }


    /**
     * 订单消息发送的库存解锁消息
     */
    @RabbitHandler
    @Transactional
    public void handlerOrderReleaseStock(OrderTo orderTo,Message message, Channel channel) throws IOException{
        log.info("订单发送的库存解锁消息-------------------------------");
        WareOrderTaskEntity orderTaskEntity = wareOrderTaskServiceImpl.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_id", orderTo.getId()));
        if(orderTaskEntity != null){
            // 等于空，说明之前锁库存时就已经回滚了，不用操作
            List<WareOrderTaskDetailEntity> taskDetailList = wareOrderTaskDetailServiceImpl.list(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", orderTaskEntity.getId()));
            for (WareOrderTaskDetailEntity taskDetailEntity : taskDetailList) {
                // 因为这个方法被执行时可能是在库存方法之后，所以需要对所有的库存详情都进行判断
                if(taskDetailEntity.getLockStatus() == 1){
                    try {
                        wareSkuServiceImpl.releaseStock(orderTaskEntity, taskDetailEntity, message, channel);
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                    } catch (IOException e) {
                        // 如果发生异常将消息重新放入队列
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                    }
                }
            }
        }
    }
}
